AggregateManyToOneAppender.java
package org.codefilarete.stalactite.engine.configurer.resolver.manytoone;
import java.util.Collections;
import org.codefilarete.reflection.AccessorChain;
import org.codefilarete.reflection.PropertyAccessor;
import org.codefilarete.stalactite.engine.configurer.model.ResolvedManyToOneRelation;
import org.codefilarete.stalactite.engine.configurer.resolver.AggregateResolver.AssemblyPoint;
import org.codefilarete.stalactite.engine.configurer.resolver.SkeletonAggregateResolver;
import org.codefilarete.stalactite.engine.runtime.ConfiguredRelationalPersister;
import org.codefilarete.stalactite.engine.runtime.load.EntityInflater.EntityMappingAdapter;
import org.codefilarete.stalactite.engine.runtime.load.EntityJoinTree;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.tool.function.Hanger.Holder;
import static org.codefilarete.stalactite.engine.runtime.load.EntityJoinTree.JoinType.OUTER;
/**
* Handles SELECT-path join-tree wiring for a {@link ResolvedManyToOneRelation}.
* Write cascades are delegated to {@link ManyToOneResolver}.
*
* @author Guillaume Mary
*/
public class AggregateManyToOneAppender {
private final ManyToOneResolver manyToOneResolver;
public AggregateManyToOneAppender(SkeletonAggregateResolver skeletonAggregateResolver) {
this.manyToOneResolver = new ManyToOneResolver(skeletonAggregateResolver);
}
/**
* Appends the given many-to-one relation to the aggregate persister by:
* - Delegating write-cascade setup to {@link ManyToOneResolver}.
* - Adding the necessary join segments to the root persister's join tree.
*
* @return an {@link AssemblyPoint} for the target entity, ready to be pushed onto the assembly queue
* so that deeper relations are also resolved
*/
public <SRC, SRCID, TRGT, TRGTID, LEFTTABLE extends Table<LEFTTABLE>, RIGHTTABLE extends Table<RIGHTTABLE>>
AssemblyPoint<?, ?, ?, ?> append(ConfiguredRelationalPersister<SRC, SRCID> rootPersister,
ResolvedManyToOneRelation<SRC, TRGT, TRGTID, LEFTTABLE, RIGHTTABLE> relation,
AssemblyPoint<SRC, SRCID, TRGT, LEFTTABLE> assemblyPawn) {
Holder<AssemblyPoint> resultHolder = new Holder<>();
manyToOneResolver.resolve(
relation,
assemblyPawn.getRelationOwnerPersister(),
targetPersister -> {
PropertyAccessor<SRC, TRGT> accessor;
if (assemblyPawn.getParentJoinPoint().equals(EntityJoinTree.ROOT_JOIN_NAME)) {
// this is the very first step (see stack seed) which is the root entity, no relation accessor shifting here
accessor = relation.getAccessor();
} else {
// we need to shift the relation accessor by the parent accessor
AccessorChain<SRC, TRGT> shifter = new AccessorChain<>(assemblyPawn.getAccessor(), relation.getAccessor());
shifter.setNullValueHandler(AccessorChain.RETURN_NULL);
accessor = shifter;
}
// we join the relation onto the aggregate root to build the whole select tree
String joinName = rootPersister.getEntityJoinTree().addRelationJoin(
assemblyPawn.getParentJoinPoint(),
new EntityMappingAdapter<>(targetPersister.<RIGHTTABLE>getMapping()),
accessor,
relation.getJoin().getLeftKey(),
relation.getJoin().getRightKey(),
null,
OUTER,
relation.getRelationFixer(),
Collections.emptySet());
resultHolder.set(new AssemblyPoint(relation.getTargetEntity(), targetPersister, joinName, accessor));
});
return resultHolder.get();
}
}